package com.qiguliuxing.dts.merchant.controller;

import com.alibaba.fastjson.JSONObject;
import com.qiguliuxing.dts.merchant.support.PermissionUtil;
import com.qiguliuxing.dts.merchant.support.VerifyCodeUtils;
import com.qiguliuxing.dts.merchant.vo.Permission;
import com.qiguliuxing.dts.common.constant.ApiAdminConsts;
import com.qiguliuxing.dts.common.util.Base64Utils;
import com.qiguliuxing.dts.common.util.ResponseUtils;
import com.qiguliuxing.dts.common.util.UUID;
import com.qiguliuxing.dts.core.annotation.aoplog.WebLog;
import com.qiguliuxing.dts.core.captcha.CaptchaCodeManager;
import com.qiguliuxing.dts.core.support.JacksonUtil;
import com.qiguliuxing.dts.db.domain.DtsAdmin;
import com.qiguliuxing.dts.merchant.support.MerchantResponseCode;
import com.qiguliuxing.dts.merchant.support.MerchantResponseUtils;
import com.qiguliuxing.dts.service.base.DtsBrandService;
import com.qiguliuxing.dts.service.base.DtsPermissionService;
import com.qiguliuxing.dts.service.base.DtsRoleService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;

@RestController
@RequestMapping("/merchant/auth")
@Validated
@Api(tags = ApiAdminConsts.Auth.PARENT)
public class MerchantAuthController {
	private static final Logger logger = LoggerFactory.getLogger(MerchantAuthController.class);

	@Autowired
	private DtsRoleService roleService;

	@Autowired
	private DtsPermissionService permissionService;

	@Autowired
	private DtsBrandService dtsBrandService;

	/**
	 * 传入的参数信息
	 * { username : value, password : value }
	 */
	@PostMapping("/login")
	@ApiOperation(value = ApiAdminConsts.Auth.LONGIN)
	@WebLog(description = ApiAdminConsts.Auth.LONGIN, persistence = true)
	public Object login(@RequestBody String body) {

		String username = JacksonUtil.parseString(body, "username");
		String password = JacksonUtil.parseString(body, "password");
		String code = JacksonUtil.parseString(body, "code");
		String uuid = JacksonUtil.parseString(body, "uuid");

		if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password) || StringUtils.isEmpty(code) || StringUtils.isEmpty(uuid)) {
			return ResponseUtils.badArgument();
		}

		// 验证码校验基于redis
		String cachedCaptcha = CaptchaCodeManager.getRedisCachedCaptcha(uuid);

		if (cachedCaptcha == null) {
			logger.error("商户管理->用户登录  错误:{},", MerchantResponseCode.AUTH_CAPTCHA_EXPIRED.desc());
			return MerchantResponseUtils.fail(MerchantResponseCode.AUTH_CAPTCHA_EXPIRED);
		}
		if (!code.equalsIgnoreCase(cachedCaptcha)) {
			logger.error("商户管理->用户登录  错误:{},输入验证码：{},后台验证码：{}", MerchantResponseCode.AUTH_CAPTCHA_ERROR.desc(),code,cachedCaptcha);
			return MerchantResponseUtils.fail(MerchantResponseCode.AUTH_CAPTCHA_ERROR);
		}
		Subject currentUser = SecurityUtils.getSubject();
		try {
			currentUser.login(new UsernamePasswordToken(username, password));
		} catch (UnknownAccountException uae) {
			logger.error("商户管理->用户登录  错误:{}", MerchantResponseCode.ADMIN_INVALID_ACCOUNT_OR_PASSWORD.desc());
			return MerchantResponseUtils.fail(MerchantResponseCode.ADMIN_INVALID_ACCOUNT_OR_PASSWORD);
		} catch (LockedAccountException lae) {
			logger.error("商户管理->用户登录 错误:{}", MerchantResponseCode.ADMIN_LOCK_ACCOUNT.desc());
			return MerchantResponseUtils.fail(MerchantResponseCode.ADMIN_LOCK_ACCOUNT);
		} catch (AuthenticationException ae) {
			logger.error("商户管理->用户登录 错误:{}", MerchantResponseCode.ADMIN_LOCK_ACCOUNT.desc());
			return MerchantResponseUtils.fail(MerchantResponseCode.ADMIN_INVALID_AUTH);
		}
		DtsAdmin admin = (DtsAdmin)currentUser.getPrincipal();
		Boolean isImproved  = dtsBrandService.checkBrandInfoImproved(admin.getBrandId());
		JSONObject result = new JSONObject();
		result.put("brandIsImproved",isImproved);
		result.put("sessionId",currentUser.getSession().getId());
		return ResponseUtils.ok(result);
	}

	/**
	 * 用户注销
	 */
	@RequiresAuthentication
	@PostMapping("/logout")
	@ApiOperation(value = ApiAdminConsts.Auth.LOGOUT)
	@WebLog(description = ApiAdminConsts.Auth.LOGOUT, persistence = true)
	public Object login() {
		Subject currentUser = SecurityUtils.getSubject();
		currentUser.logout();
		return ResponseUtils.ok();
	}

	@RequiresAuthentication
	@GetMapping("/info")
	@ApiOperation(value = ApiAdminConsts.Auth.INFO)
	@WebLog(description = ApiAdminConsts.Auth.INFO)
	public Object info() {
		Subject currentUser = SecurityUtils.getSubject();
		DtsAdmin admin = (DtsAdmin) currentUser.getPrincipal();

		Map<String, Object> data = new HashMap<>();
		data.put("name", admin.getUsername());
		data.put("avatar", admin.getAvatar());

		Integer[] roleIds = admin.getRoleIds();
		Set<String> roles = roleService.queryByIds(roleIds);
		Set<String> permissions = permissionService.queryByRoleIds(roleIds);
		data.put("roles", roles);
		// 这里需要转换perms结构，因为对于前端而已API形式的权限更容易理解
		data.put("perms", toAPI(permissions));

		return ResponseUtils.ok(data);
	}

	@Autowired
	private ApplicationContext context;
	private HashMap<String, String> systemPermissionsMap = null;

	private Collection<String> toAPI(Set<String> permissions) {
		if (systemPermissionsMap == null) {
			systemPermissionsMap = new HashMap<>();
			final String basicPackage = "com.qiguliuxing.dts.merchant";
			List<Permission> systemPermissions = PermissionUtil.listPermission(context, basicPackage);
			for (Permission permission : systemPermissions) {
				String perm = permission.getRequiresPermissions().value()[0];
				String api = permission.getApi();
				systemPermissionsMap.put(perm, api);
			}
		}

		Collection<String> apis = new HashSet<>();
		for (String perm : permissions) {
			String api = systemPermissionsMap.get(perm);
			apis.add(api);

			if ("*".equals(perm)) {
				apis.clear();
				apis.add("*");
				return apis;
			}
		}
		return apis;
	}
	
	/**
     * 生成验证码
     */
	@GetMapping("/captchaImage")
	@ApiOperation(value = ApiAdminConsts.Auth.CAPTCHA)
	public Object getCode(HttpServletResponse response) throws IOException {
        // 生成随机字串
        String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
        // 唯一标识
        String uuid = UUID.randomUUID().toString(true);
        boolean successful = CaptchaCodeManager.addToRedisCache(uuid, verifyCode,10);

		if (!successful) {
			logger.error("请求验证码出错:{}", MerchantResponseCode.AUTH_CAPTCHA_FREQUENCY.desc());
			return MerchantResponseUtils.fail(MerchantResponseCode.AUTH_CAPTCHA_FREQUENCY);
		}
        // 生成图片
        int w = 111, h = 36;
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        VerifyCodeUtils.outputImage(w, h, stream, verifyCode);
        try {
        	Map<String, Object> data = new HashMap<>();
            data.put("uuid", uuid);
            data.put("img", Base64Utils.encode(stream.toByteArray()));
            return ResponseUtils.ok(data);
        } catch (Exception e){
            e.printStackTrace();
            return ResponseUtils.serious();
        } finally {
            stream.close();
        }
    }

	@GetMapping("/401")
	public Object page401() {
		return ResponseUtils.unlogin();
	}

	@GetMapping("/index")
	@WebLog(description = "检查服务启动是否正常")
	public Object pageIndex() {
		return ResponseUtils.ok();
	}

	@GetMapping("/403")
	public Object page403() {
		return ResponseUtils.unauthz();
	}
}
